<template>
  <div class="breadcrumb-wrapper">
    <div class="leftx">
      <!-- <el-icon><ArrowLeftBold /></el-icon> -->
      <el-breadcrumb separator-icon="ArrowRight" class="breadcrumb-w">
        <template v-for="(item, index) in breadcrumbList" :key="item.id">
          <el-breadcrumb-item @click="handleToFolder(item, index)">
            <div :class="{ isActive: index !== breadcrumbList.length - 1 }">
              <el-text style="max-width: 100px; height: 16px" truncated>{{
                item.label
              }}</el-text>
            </div>
          </el-breadcrumb-item>
        </template>
      </el-breadcrumb>
    </div>
    <div class="rightx">
      <div class="ai-recognition">
        <el-popover
          class="custom-popover-crumb-style"
          placement="top-end"
          trigger="hover"
          popper-class="custom-popover-crumb-style"
          popper-style="width: fit-content"
          :teleported="false"
        >
          <template #reference>
            <div
              id="ai-recognition"
              style="
                font-size: 14px;
                cursor: pointer;
                display: flex;
                align-items: center;
              "
            >
              <el-icon style="font-size: 32px; color: #4093ff">
                <AiIcon></AiIcon>
              </el-icon>
              笔记
            </div>
          </template>
          <div class="ai-assistant">
            <el-divider content-position="left"> AI助手</el-divider>
          </div>
          <div
            v-if="dataList.length"
            style="
              display: flex;
              max-width: 300px;
              flex-wrap: wrap;
              column-gap: 20px;
              overflow: hidden;
            "
          >
            <div v-for="(item, index) in dataList" :key="index">
              <el-tooltip
                :effect="'dark'"
                :content="item.title"
                placement="top"
                trigger="hover"
                append-to="#ai-recognition"
              >
                <el-image
                  fit="cover"
                  :src="imagePrefix + item.avatar"
                  class="border-radius-s"
                  style="width: 32px; height: 32px; cursor: pointer"
                  @click="handleAiAssistant(item)"
                >
                  <template #error>
                    <div class="image-slot">
                      <el-icon>
                        <text-avatar :text="item.title" :width="34"/>
                      </el-icon>
                    </div>
                  </template>
                </el-image>
              </el-tooltip>
            </div>
          </div>
          <div class="tool-assistant">
            <el-divider content-position="left"> 工具助手</el-divider>
            <el-tooltip
              :effect="'dark'"
              content="图片文字识别"
              placement="top"
              trigger="hover"
            >
              <el-icon
                style="font-size: 32px; cursor: pointer"
                @click="ocrVisible = true"
              >
                <Ocr></Ocr>
              </el-icon>
            </el-tooltip>
          </div>
        </el-popover>
      </div>
      <slot></slot>
    </div>
  </div>

  <el-dialog v-model="ocrVisible" width="800" @close="handleCloseOcr" draggable>
    <div class="scan-wrapper">
      <div class="scan-left">
        <div class="uploads">
          <image-show
            v-model:list="ocrImages.images"
            :limit="1"
            :showDrag="false"
            :multiple="false"
          />
        </div>
        <el-button
          type="primary"
          :disabled="!ocrImages.images.length"
          @click="handleScanImg"
          >开始识别
        </el-button>
      </div>
      <div class="scan-right">
        <el-input
          v-model="ocrText"
          style="
            width: 500px;
            height: 100%;
            border: none !important;
            box-shadow: none !important;
          "
          :autosize="{ minRows: 7, maxRows: 20 }"
          resize="none"
          type="textarea"
          readonly
        />
      </div>
    </div>
    <template #header>
      <el-icon>
        <component is="EditPen" />
      </el-icon>
      OCR图片识别
    </template>
    <template #footer>
      <div class="dialog-footer">
        <el-button :disabled="!ocrText" @click="handleCopy(ocrText)"
          >复制
        </el-button>
        <el-button
          type="primary"
          :disabled="!ocrText"
          @click="handleSaveNote(ocrText)"
        >
          保存为笔记
        </el-button>
      </div>
    </template>
  </el-dialog>
  <el-dialog
    :title="assistantData.title"
    v-model="assistantVisible"
    width="1000"
    @close="closeAssistant"
    top="7vh"
  >
    <div class="flex justify-content-between gap-10">
      <div class="assistant-item">
        <el-form
          ref="appInputForm"
          :model="appInputData"
          :rules="appInputRules"
          label-position="top"
          style="width: 259px"
        >
          <el-form-item
            v-for="(f, k) in assistantData.option_message"
            :prop="`field_${k}`"
            :label="f.title"
          >
            <el-input
              type="text"
              v-model="appInputData[`field_${k}`]"
              maxlength="200"
              :placeholder="f.placeholder"
              v-if="f.input_type === 'text'"
            />
            <el-input
              type="textarea"
              v-model="appInputData[`field_${k}`]"
              maxlength="2000"
              :placeholder="f.placeholder"
              v-if="f.input_type === 'textarea'"
              :rows="4"
            />
            <el-select
              v-model="appInputData[`field_${k}`]"
              :placeholder="f.placeholder"
              v-if="f.input_type === 'select'"
            >
              <el-option v-for="op in f.options" :label="op" :value="op" />
            </el-select>
            <el-radio-group
              v-model="appInputData[`field_${k}`]"
              class="radio-app-input"
              v-if="f.input_type === 'radio'"
            >
              <el-radio v-for="op in f.options" :value="op" :label="op" />
            </el-radio-group>
            <el-checkbox-group
              v-model="appInputData[`field_${k}`]"
              class="radio-app-input"
              v-if="f.input_type === 'checkbox'"
            >
              <el-checkbox v-for="op in f.options" :value="op" :label="op" />
            </el-checkbox-group>
          </el-form-item>
          <el-form-item
            :prop="`field_0`"
            v-if="assistantData.option_message.length === 0"
            label="提问内容"
          >
            <el-input
              type="textarea"
              v-model="appInputData.field_0"
              maxlength="2000"
              placeholder="请输入您的问题..."
            />
          </el-form-item>
        </el-form>
        <el-button type="primary" class="w-260" @click="handleSubmitApp"
          >提 交</el-button
        >
      </div>
      <div class="assistant-item right">
        <markdown-viewer
          id="assistant-content"
          :value="aiOutputText"
          v-if="aiOutputText !== ''"
        />
      </div>
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button :disabled="!isOutput" type="danger" @click="stopChat"
          >停止
        </el-button>
        <el-button
          :disabled="!aiOutputText || isOutput"
          @click="handleCopy(aiOutputText)"
          >复制
        </el-button>
        <el-button
          type="primary"
          :disabled="!aiOutputText || isOutput"
          @click="handleInsertToNote(aiOutputText)"
          v-if="
            props.breadcrumbList.length &&
            props.breadcrumbList[props.breadcrumbList.length - 1].icon ===
              'Document'
          "
          >一键插入到笔记
        </el-button>
        <el-button
          type="primary"
          :disabled="!aiOutputText || isOutput"
          @click="handleSaveNote(aiOutputText)"
          >保存为笔记
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>
<script setup>
// import { ArrowLeftBold } from '@element-plus/icons-vue'
// import { Picture as IconPicture } from '@element-plus/icons-vue'
import TextAvatar from '@/components/text-avatar/index.vue'
const imagePrefix = import.meta.env.VITE_IMAGE_SUFFIX
import Ocr from '@/icons/Ocr.vue'
import { httpAppList, httpSelectApp } from '@/api/application.js'
import ImageShow from '@/components/image-show/index.vue'
import AiIcon from '@/icons/Ai.vue'
import { copyString, jsonToObject } from '@/utils/index'
import { ref, reactive, onMounted, nextTick, computed } from 'vue'
import useNoteStore from '@/stores/note'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import { httpImageOcr, httpCreateNote } from '@/api/note.js'
import { ElLoading, ElMessage } from 'element-plus'
import { defaultChat, knowledgeChat } from '@/api/chat.js'
import MarkdownViewer from '@/components/markdown-viewer/index.vue'

const router = useRouter()
const noteState = useNoteStore()
const { selectedFolder, wangEditorRef } = storeToRefs(noteState)
const props = defineProps({
  breadcrumbList: {
    type: Array,
    default: () => [],
  },
})
const loading = ref(false)
const dataList = ref([])
const listTotal = ref(0)
const query = reactive({
  classification_id: 0,
  knowledge_id: 0,
  page: 1,
  limit: 20,
  keyword: '',
  is_owner: 0,
  is_note: 1,
})
const ocrImages = reactive({
  view: '',
  images: [],
})
const ocrVisible = ref(false)
const ocrText = ref('')
// 一键插入到笔记
const handleInsertToNote = (aiOutputText) => {
  wangEditorRef.value.focus()
  wangEditorRef.value.insertText(aiOutputText)
  assistantVisible.value = false
}
const handleToFolder = (item, index) => {
  if (index === props.breadcrumbList.length - 1) return
  selectedFolder.value = {
    type: 1,
    id: item.id,
    // label: item.name,
    label: item.label,
  }
  router.push('/file/note/' + item.id)
}
const handleCloseOcr = () => {
  ocrVisible.value = false
  ocrImages.images = []
  ocrImages.view = ''
}
/**
 * 开始识别
 */
const handleScanImg = async () => {
  const load = ElLoading.service({ fullscreen: true, text: '努力识别中...' })
  const res = await httpImageOcr(ocrImages.images[0], 1).catch(() => null)
  load.close()
  if (!res) return
  const { result } = res
  ocrText.value = result
  ocrImages.images = []
}
/**
 * 复制
 * @param {*} value
 */
const handleCopy = (value) => {
  // ocrVisible.value = false
  copyString(value)
}
/**
 * 保存为笔记
 */
const handleSaveNote = (text) => {
  const pattern = /[\s\n.,!?;:，。！？；：’‘”“'"(){}（）【】[\]《》<>\\\/\-]/g
  httpCreateNote({
    folder_id: 0,
    title: text.replace(pattern, '').substring(0, 8),
    content: text,
    icon: 'Document',
    label_id_list: [],
  })
    .then(() => {
      ElMessage.success('已加入笔记，请在笔记中查看和编辑')
      noteState.getFolderListData()
    })
    .catch(() => {})
}

const getList = async () => {
  const storageKey = 'note-ai-application-list'
  if (query.page === 1) {
    const cacheData = window.sessionStorage.getItem(storageKey)
    if (cacheData) {
      const { list, total } = JSON.parse(cacheData)
      dataList.value = list
      listTotal.value = total
      return
    }
  }
  loading.value = true
  const response = await httpAppList({ ...query }).catch(() => null)
  loading.value = false
  if (!response) return
  const { list, total } = response
  dataList.value = list
  listTotal.value = total
  if (query.page === 1) {
    window.sessionStorage.setItem(
      storageKey,
      JSON.stringify({
        list: list,
        total: total,
      }),
    )
  }
}
onMounted(() => {
  getList()
})

const assistantData = reactive({
  id: 0,
  avatar: '',
  character: '',
  introduction: '',
  knowledge_id: [],
  title: '',
  target: '',
  option_message: [],
})

const appInputData = reactive({})
const appInputRules = {}
const isOutput = ref(false)
const aiOutputText = ref('')
/**
 *
 * @type {Ref<UnwrapRef<FormInstance>>}
 */
const appInputForm = ref(null)
const assistantVisible = ref(false)
let chatController = null

const closeAssistant = () => {
  assistantVisible.value = false
}

const handleAiAssistant = (item) => {
  if (item.id !== assistantData.id) {
    aiOutputText.value = ''
  }
  Object.keys(assistantData).forEach((key) => {
    if (['option_message', 'knowledge_id'].includes(key)) {
      assistantData[key] = JSON.parse(item[key])
    } else {
      assistantData[key] = item[key]
    }
  })
  initAppInputForm()
  assistantVisible.value = true
}

const initAppInputForm = () => {
  Object.keys(appInputData).forEach((key) => {
    delete appInputData[key]
  })
  Object.keys(appInputRules).forEach((key) => {
    delete appInputData[key]
  })
  if (!assistantData.option_message) {
    const field = `field_0`
    appInputData[field] = ''
    appInputRules[field] = [
      {
        required: true,
        message: '此项为必填项',
      },
    ]
  } else {
    assistantData.option_message.forEach((item, index) => {
      const field = `field_${index}`
      const { input_type, is_must } = item
      appInputData[field] = input_type === 'checkbox' ? [] : ''
      appInputRules[field] = [
        {
          required: is_must,
          message: '此项为必填项',
        },
      ]
    })
  }
  nextTick(() => {
    setTimeout(() => {
      if (appInputForm.value && appInputForm.value.clearValidate) {
        appInputForm.value.clearValidate()
      }
    }, 300)
  })
}

const handleSubmitApp = async () => {
  const valid = await appInputForm.value.validate((valid) => valid)
  if (!valid) return
  // 拼接app输入内容
  let content = ''
  assistantData.option_message.forEach((item, index) => {
    if (content !== '') {
      content += '\n'
    }
    const { take_title, input_type, title } = item
    if (take_title) {
      content += title + ':'
    }
    let input = appInputData[`field_${index}`]
    if (input_type === 'checkbox') {
      input = input.join(',')
    }
    content += input
  })
  if (!content) {
    return
  }
  await httpSelectApp(assistantData.id).catch(() => null)
  requestChat(content)
}

const getChatFunction = computed(() => {
  if (assistantData.knowledge_id.length && assistantData.knowledge_id[0]) {
    return knowledgeChat
  } else {
    return defaultChat
  }
})

const requestChat = (message) => {
  isOutput.value = true
  getChatFunction
    .value({
      knowledge_id: assistantData.knowledge_id.length
        ? assistantData.knowledge_id[0]
        : 0,
      message: message,
      conversation_id: undefined,
      history: [],
      score_threshold: 0.7,
      application_id: assistantData.id,
      application_msg: { ...assistantData },
    })
    .then(({ reader, control }) => {
      chatController = control
      aiOutputText.value = ''
      handleReader(reader)
    })
}

const handleReader = async (reader) => {
  let d, v
  try {
    const { value, done } = await reader.read()
    d = done
    v = value
  } catch (e) {
    d = true
  }
  const decoder = new TextDecoder()
  if (!d) {
    let data = decoder.decode(v.buffer)
    aiOutputText.value += data
    await handleReader(reader)
  } else {
    if (v) {
      let data = decoder.decode(v.buffer)
      aiOutputText.value += data
    }
    const json = jsonToObject(aiOutputText.value)
    if (json !== null && json.code !== 200) {
      aiOutputText.value = ''
      ElMessage.error(json.message)
    }
    isOutput.value = false
  }
}

const stopChat = () => {
  if (chatController) {
    chatController.abort()
    isOutput.value = false
  }
}
</script>
<style scoped lang="scss">
.breadcrumb-wrapper {
  // min-width: 80%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 4px;
  .leftx {
    flex: 1;
    // // flex-shrink: 0;
    // display: flex;
    // flex-wrap: nowrap;
  }

  .rightx {
    width: 200px;
    justify-content: space-between;
    display: flex;
    flex-shrink: 0;
  }
  .breadcrumb-w {
    width: 100%;
    display: flex;
    flex-wrap: nowrap;
    // @include textBeyondOmit;
  }
}

.scan-wrapper {
  display: flex;
  gap: 10px;

  .scan-left {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: flex-end;
    gap: 10px;

    .uploads {
      max-height: 300px;
      overflow-y: auto;
      width: 100%;
      border: 1px solid #ccc;
      padding: 10px;
    }
  }

  .scan-right {
    flex: 1;
    max-height: 500px;
    background-color: #f2f2f2;
    border-radius: 5px;

    :deep(.el-textarea__inner) {
      background-color: #f2f2f2 !important;
      box-shadow: none !important;
    }
  }
}

/* 滚动条样式 */
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

/* 滑块样式 */
::-webkit-scrollbar-thumb {
  background-color: #9f9f9f;
  border-radius: 10px;
}

/* 滚动条轨道样式 */
::-webkit-scrollbar-track {
  background-color: #fcfcfc;
  border-radius: 10px;
}

.isActive {
  font-weight: 600;
  cursor: pointer;
}

.assistant-item {
  height: 100%;
  max-height: calc(90vh - 200px);
  min-height: 200px;
  width: 400px;
  overflow-y: auto;
  overflow-x: hidden;

  &.right {
    background: #efefef;
    height: auto;
    width: 600px;
    padding: 10px 15px;
  }
}
</style>
<style>
.custom-popover-crumb-style {
  padding: 4px !important;
}
</style>
